.TITLE DCCTL - Control Operations .IDENT /05.00/ .IF DF D$$CHE ; ; Copyright (c) 1995-1999 by Mentec, Inc., U.S.A. ; All rights reserved. ; ; Original author: ; John Gemignani ; ; Modified by: ; ; J. Kauffman 29-Mar-88 03.01 ; ; Re-mastered for RSX-11M-PLUS V4.4 by: ; ; L.B.McCulley 29-Dec-91 4.00 ; D. Carroll 19-Jul-92 4.00e ; D. Carroll 05-August-1992 4.01 ; L. B. McCulley 8-Aug-92 4.01a ; D. Carroll 30-Oct-1992 4.03 ; ; Modified for RSX-11M-PLUS V4.5 by: ; ; D. Carroll 07-June-1993 4.04 ; DC221 - Correct implicit deactivation path if no ; fork is ever required. ; ; Modified for RSX-11M-PLUS V4.6 by: ; ; D. Carroll 08-Jan-1996 05.00 ; DC430 - Include support for 32-bit LBNs ; ; ; This module contains the code to perform the cache operations required ; QIOs with IO.STC function codes. ; .MCALL PCBDF$ PCBDF$ .PSECT DC$CTL, RO, I .SBTTL DCCTL1 - Control operations phase 1 - dispatcher ;+ ; IO.STC function code QIOs are used to communicate with the cacher ; ; There are two types of interest to us: ; (a third, I.PRM+2 equal VV$SIZ (only negative value expected for I.PRM ; goes immediately to the driver with no processing or implication in cache ; ; I.PRM+2 = VV$CHE ; this explicitly identifies control functions intended for ; the data cache code. I.PRM+4 is a specific function code ; These are sent by the MCR SET /CACHE commands (in ST5OV) ; and by the block deallocation routines in F11ACP (in SMDEL) ; ; I.PRM+2 not equal VV$SIZ and not equal VV$CHE ; this is an implicit termination of caching for the device ; ; ; (there is no implementation of automatic activation of cache on mounts ; although vestigial code for this is present and commented out prior to ; M-PLUS V4.4. this code is untested and should be regarded as very suspect ; ; ; Passed: ; UCBX mapped in APR6 ; X.CSTS := Unit's cache status (i.e. selected operations) ; ; R1 -> I/O packet ; I.PRM+2 := Operation code ; R5 -> UCB ; ; Returned: ; All registers preserved ; ; Otherwise N/A - control is passed to $DRQRQ ; ; Action: ; ; Notes: ; QIOs which are NOT transfer functions do not have I.PRMs ; adjusted for the address doublewords. Therefore, all ; parameters will be in the same cells within I.PRM as they ; are issued (hence the Px definitions in DCPRE should not be used ;- DCCTL1::TST I.PRM+2(R1) ; Is this a "size" operation? BMI 90$ ; If MI, yes, forward to driver CMP #VV$CHE, I.PRM+2(R1) ; A cache directed operation? BEQ CHEFUN ; If EQ, yes, go do it BITB #XC.ACT, APR6.BASE+X.CSTS ; Is this device caching BEQ 90$ ; If EQ, no, send to driver now ;+ ; This block of code is entered by IO.STC functions with I.PRM not equal ; to either VV$SIZ or VV$CHE. It implements the implicit deactivation of ; cache for all other disk device IO.STC functions except for port-specic ; set functions (because they could be HRC bringing the second port of a ; dual-ported unit online and should not deactivate cache if it is already ; active on the first port). ;- .IF DF M$$ACD ; multi-access device support CMP I.PRM+2(R1),#VV$SET ; is this a set VV operation? BNE 70$ ; if NE, nope deactivate cache TST I.PRM+4(R1) ; is this port relative I/O BLE 70$ ; nope, continue processing BIT #S2.MAD,S.ST2(R4) ; this better be a multi-port device BNE 90$ ; if NE, yes, don't deactivate cache .ENDC ;DF M$$ACD ;+ ; The implicit deactivation of cache is deemed to indicate a transition ; of VV$SET or VV$CLR, either of which should imply that file volume content ; is not meaningful. Thus all extents are flushed without regard to whether ; they are deferred temporary file extents that have not been written to disk ; The implication of a transition in volume valid is that temp files are not ; valid either. ;- 70$: BITB #X2.DEA,APR6.BASE+X.CST2 ; is cache being deactivated? BEQ DACJMP ; no, go ahead and process CALLR Q2DRVR ; yes, this one waits for rundown 90$: SEC ; else no, give to driver RETURN .SBTTL DCCTL2 - Cache Control Phase 2 processing ;+ ; DCCTL2 - Phase 2 processing for control functions simply restarts them ; because they were queued to some busy extent until it went unbusy. ; ; Input: ; R1 - URP ; R5 - UCB address ; UCBX mapped ;- DCCTL2::CMP #VV$CHE,I.PRM+2(R1) ; explicit cache function? BEQ SUBFUN ; yes, dispatch it (again) DACJMP: JMP CHEDAC ; no, must be implicit deactivation .SBTTL + CHEFUN - Cache Function (VV$CHE) processing ;+ ; **-CHEFUN- Cache Function (VV$CHE) processing ; ; Passed: ; R1 -> I/O packet ; I.TCB -> TCB of issuing task ; T.ST3 := T3.PRV indicates privileged task ; ; Returned: ;;; N/A - control is passed to $IOFIN ; ; Action: ; ; This code validates the cache function as issued by a privileged ; user, and initializes the word at I.PRM as zero for the count of ; bytes returned by the function. Function processing routines set ; the count as needed, and deactivation uses this word as a flag to ; show Phase II invocation. ; CHEFUN: CLR I.PRM(R1) ; Clear byte count returned MOV I.TCB(R1), R0 ; Get the TCB of issuer BNE 10$ ; If EQ, got it FATAL$ BE.UCB 10$: BIT #T3.PRV, T.ST3(R0) ; Is the task privileged BNE SUBFUN ; NE, ok, dispatch subfunction ; If EQ, no, error! FUNPRI: MOV #,R0 ; Set "privilege violation" BR FUNEXT ; Proceed to common exit point FUNBAD: MOV #,R0 ; Set "bad parameters" BR FUNEXT ; Proceed to common exit point ;+ ; SUBFUN routines common exit ; ; Common local I/O completion occurs here. Offset I.PRM+P6.1 ; will contain the primary status, and I.PRM+P6.2 will contain ; the secondary status (or byte count). ;- FUNSUC: MOV #IS.SUC,R0 ; Return successful status FUNEXT: MOV R1, R3 ; Establish context for IOC MOV I.PRM(R3), R1 ; Set secondary status CALL $IOFIN ; Complete this request CLR R1 ; Tell $DRQRQ we did it RETURN .SBTTL SUBFUN - Cache-specific Subfunctions ;+ ; **-SUBFUN- Cache-specific Subfunctions ; ; Passed: ; R1 -> I/O packet ; I.PRM+4 := Subfunction code ; ; Returned: ; ; Action: ; This routine will process the various subfunctions: ; ; 1. FUNENA - Enable cache processing ; 2. FUNDIS - Disable cache processing ; 3. FUNACT - Activate cache processing ; 4. FUNDAC - Deactivate cache processing ; 5. FUNRCS - Read cache parameters ; 6. FUNSCS - Set cache parameters ; 7. FUNCSB - Clear statistics buffer ; 8. FUNRSB - Read statistics buffer ; 9. FUNDEL - Delete blocks from cache (called from SMDEL in F11ACP) ; ; ; Notes: ; The first two words of the parameter list may be needed for ; Phase 2 processing to identify the VV$CHE subfunction of IO.STC. ; They were previously used to return the status to the calling ; routine (which handled the call to $IOFIN). This has been changed ; IS.SUC is now assumed to be the primary status, with routines to ; the error code to be returned in R0 if otherwise. I.PRM is now ; secondary status (byte count). I.PRM is also used to flag Phase II ; for deactivation requests, so that multiple deactivations can be ; prevented (to avoid messy races). I.PRM is initially cleared in ; CHEFUN which validates the function code before calling SUBFUN to ; dispatch the function. Phase II enters DCCTL2 which calls SUBFUN ; directly, avoiding the initialization of I.PRM to preserve the flag ; status across Phase II dispatch. It is not possible to allocate ; a CRP because a cache partition cannot be assumed. ;- SUBFUN: MOV I.PRM+4(R1), R0 ; Get the subfunction code (P3) DEC R0 ; normalize index BLE FUNBAD ; not a valid code if zero or negative CMP R0, #DC$MAX ; within valid range? BGT FUNBAD ; no, error CMP R0, #DC$CSB-1 ; is cache required to be active? BLO 10$ ; if LO, nope, do the work BITB #XC.ACT, APR6.BASE+X.CSTS ; is cache active? BEQ FUNPRI ; nope, return privilege violation BITB #X2.DEA, APR6.BASE+X.CST2 ; being deactivated? BNE FUNPRI ; if NE, return priv violation 10$: ASL R0 ; form a word index CALLR @20$(R0) ; and dispatch by function 20$: FUNENA ; enable cache FUNDIS ; disable cache FUNACT ; activate cache FUNDAC ; deactivate cache FUNRCS ; read cache status FUNSET ; set cache options FUNCSB ; clear statistics buffer FUNRSB ; read statistics buffer FUNDEL ; delete extents DC$MAX= .-20$ / 2 .SBTTL + DC$ENA - Enable Cache ; ; This function is simple, since it does not require any ; form of validation. It is merely used to set a status ; bit. ; FUNENA: ; BISB #XC.ENA, APR6.BASE+X.CSTS ; Set autoactivation on BR FUNSUC .SBTTL + DC$DIS - Disable the cache ; ; This function is simple, since it does not require any ; form of validation. It is merely used to clear a status ; bit. ; FUNDIS: BICB #XC.ENA, APR6.BASE+X.CSTS ; Clear autoactivation on BR FUNSUC .SBTTL + FUNACT - Activate cache ; ; Passed: ; UCBX mapped in APR6 ; ; R5 -> UCB ; ; Action: ; This function will activate cache for a device which does ; not have caching currently activated for it. Note that ; this operation can be used to "bypass" the "autoactivation ; on mount" bit (XC.ENA=1). In other words, if the cache ; is disabled for a device, FUNACT can turn caching on for ; the device regardless of the setting of XC.ENA. FUNACT ; will not change the setting of XC.ENA either. Therefore, ; a disk with autoactivation disabled will remain that way ; independent of FUNACT. ;- FUNACT: BITB #X2.DEA, APR6.BASE+X.CST2 ; deactivation in process BNE FUNPRI ; yes, punt w/ priv error ; to avoid racing deactivate BITB #XC.ACT, APR6.BASE+X.CSTS ; Cache already activate BNE FUNSUC ; If NE, yes - don't bother CALL CHEACT ;Activate the cache for this device BCC FUNSUC ;Return success if carry clear, BR FUNPRI ;Privilege violation if failure .SBTTL + FUNDAC - deactivate cache ; ; Passed: ; UCBX mapped in APR6 ; R1 -> packet ; R5 -> UCB ; ; Action: ; Errors will be returned if cache is not active, or if deactivation ; is already in progress (this is necessary to avoid races, multiple ; decrements of P.RMCT, etc.). The internal routine CHEDAC will be ; used for processing common to both implicit and explicit deactivation ; ;- FUNDAC: BITB #XC.ACT, APR6.BASE+X.CSTS ; Cache activate? BEQ FUNPRI ; no, return priv error TST I.PRM(R1) ; byte cnt flags Phase I BNE 10$ ; Phase II, skip status BITB #X2.DEA, APR6.BASE+X.CST2 ; deactivation in proces BNE FUNPRI ; yes, punt w/ priv error 10$: INC I.PRM(R1) ; show Phase II next pass CALLR CHEDAC ; finish deactivation .SBTTL + DC$RCS - Read cache parameters ; ; This function will return the current setting of the cache ; in the second status word of the I/O status block. ; FUNRCS: MOVB APR6.BASE+X.CSTS, I.PRM(R1) ; Set the status bits BR FUNSUC .SBTTL + DC$SET - Set cache parameters ; ; Passed: ; UCBX mapped in APR6 ; X.CSTS := XC.ACT indicates unit is active (in terms of cache) ; X.CPCB -> PCB of region unit is caching through ; ; R1 -> I/O packet ; I.PRM+6 := Set parameters ; I.PRM+10 -> Cache partition PCB ; I.PRM+12 -> Extent limits ; ; Returned: ; R1 -> I/O packet ; I.PRM, +2 := Completion status ; ; Action: ; This function will set the lower cache status bits of the X.CSTS ; ; The high bit of the word indicates that the partition PCB has been ; passed in parameter 5 and which should be plugged into X.CPCB. ; ; Note: ; To enable/disable and activate/deactivate cache use corresponding ; subfunction codes. ; VALID= .IIF DF,CHEWBH, VALID = VALID!DC$WBH INVALID=^C FUNSET: MOV I.PRM+6(R1), R0 ; Get the status bits BIT #INVALID, R0 ; Invalid bits in here? BNE FUNBAD ; Return "bad parameters" error .IFDF CHEDFR BITB #XC.DFR,R0 ; Is deferred writes on in new version BEQ 15$ ; If EQ, no, don't worry BITB #XC.DAT,R0 ; Is virtual turned on as well BEQ FUNBAD ; If EQ, no, disallow 15$: .ENDC ;IFDF,CHEDFR MOV I.PRM+10(R1), R0 ; Get address of requested cache CALL VALPCB ; validate the PCB address passed BCS FUNBAD ; nfg BITB #XC.ACT, APR6.BASE+X.CSTS ; Is current PCB address BNE 19$ ; If NE, yes MOV R0, APR6.BASE+X.CPCB ; Load into the UCBX BR 20$ 19$: CMP R0, APR6.BASE+X.CPCB ; Do they match each other? BNE PRIJMP ; If NE, no 20$: MOV R1, -(SP) ; Save the I/O packet address MOV I.PRM+12(R1), R0 ; Get virtual address of extent MOV #5, R1 ; Length of extent limit table CALL $ACHKB ; Address check BCC 21$ ; If CC, okay MOV (SP)+, R1 ; Restore I/O packet address JMP FUNBAD ; Otherwise part not in virtual 21$: CALL $RELOC ; Calculate parameters for $BLXIO ; ; Context: ; R1 := Physical addess of table in 32-word blocks ; R2 := Offset of table, bias APR6 ; MOV #5, R0 ; Length of extent limit table SUB #20000, R2 ; Change into APR5 offset MOV KISAR6, R3 ; Physical address of UCBX MOV #APR6.BASE+X.XDAT, R4 ; Offset of table in UCBX, bias CALL $BLXIO MOV (SP)+, R1 ; Restore I/O packet address ; ; Note: ; DC$PAR bit is ignored by following byte instruction. ; BICB #VALID, APR6.BASE+X.CSTS ; Clear original status BISB I.PRM+6(R1), APR6.BASE+X.CSTS ; Set new status bits .IF DF CHEWBH BICB #X2.WBH,APR6.BASE+X.CST2 ; remove write behind status BIT #DC$WBH,I.PRM+6(R1) ; should we enable it? BEQ 22$ ; nope, skip this ... BISB #X2.WBH,APR6.BASE+X.CST2 ; allow write-behind to occur 22$: .ENDC ;DF,CHEWBH BIT #DC$DBG,I.PRM+6(R1) ; should debug be enabled? BEQ 23$ ; nope, continue ... MP.PAR ; map to the partition BISB #CS.DBG,APRD.BASE+H.CSTS ; set the status 23$: JMP FUNSUC ; ok, we are done now, return status PRIJMP: JMP FUNPRI .SBTTL + FUNCSB - Clear statistics buffer ; ; This function maps the statistics buffer ; (if any) and fills it with nulls. ; ; The statistics buffer is allocated in secondary pool ; and is a single 32-word block of 16 doublewords. ; ; NOTE: Access to the UCBX is lost by this routine! ; There is currently no reason to save (reload) this ; address since the UCBX is no longer needed. ; FUNCSB: MOV APR6.BASE+X.CSBA,KISAR6 ;Map statistics buffer in APR6 BEQ 20$ ;Ooops, statistics buffer not here MOV #APR6.BASE,R0 ;Point R0 to it MOV #S.SIZE/4,R3 ;Count of cells to clear 10$: CLR (R0)+ ;Clear out first word CLR (R0)+ ;Clear out second word SOB R3, 10$ ;More to clear out? 20$: JMP FUNSUC ;Proceed to common exit .SBTTL + DC$RSB - Read statistics buffer ; ; Passed: ; UCBX mapped in APR6 ; ; R1 -> I/O packet ; I.PRM+6 -> User buffer (virtual address) ; I.PRM+10 -> Size of user buffer ; ; Returned: ; ; Action: ; This function will return the contents of the cache ; statistics buffer for a particular device. The caller ; must pass the address and length of his buffer in ; parameters 5 and 6 (respectively). The user's context ; is currently loaded, and $ACHCK is called to validate ; the buffer. The buffer could be any size smaller or ; equal to the stats buffer. It should NOT be allowed ; to be larger, since this will allow him to read ; either the rest of secondary pool, or off the end of ; secondary pool (into a task, common, or non-existent ; memory). Nonexistent memory (odd addresses) in kernel ; mode spells instant doom. ; ; $BLXIO will be used to teleport the stats buffer from ; secondary pool to the user's buffer. ; ; NOTE: $ACHCK is used instead of $CKBFx because the operation ; will be completed immediately (while the user remains ; loaded). $RELOC is called to create the context for ; $BLXIO (address doubleword). ; FUNRSB: TST APR6.BASE+X.CSBA ;Statistics buffer available? BEQ PRIJMP ;No buffer if EQ; return error MOV R1,-(SP) ;Save the packet's address MOV I.PRM+6(R1),R0 ;Load the user's virtual address MOV I.PRM+10(R1),R1 ;Load the user's buffer length CALL $ACHCK ;Address check loaded user space BCC 5$ ;Address check failed, return error MOV (SP)+,R1 ;Get packet's address JMP FUNBAD ;Return "bad parameters" 5$: CALL $RELOC ;Now create the address doubleword MOV R1, R3 ;Prepare parameters for $BLXIO MOV R2, R4 MOV (SP),R1 ;Get back packet's address MOV I.PRM+10(R1),R0 ;Get the count of bytes to move CMP R0,#S.SIZE ;User want more than available? BLOS 10$ ; If LOS, no, accept it MOV #S.SIZE,R0 ;Else enforce limit 10$: MOV R0,I.PRM(R1) ;Return the byte count MOV APR6.BASE+X.CSBA,R1 ;Get statistics buffer APR bias MOV #APR5.BASE,R2 ;Set the displacement CALL $BLXIO ;Transfer the statistics buffer MOV (SP)+,R1 ;Packet's address to R1 JMP FUNSUC ;Proceed to common exit .SBTTL + FUNDEL - Cache delete extents subfunction ; ; Invoked: ; from SMDEL in F11ACP to delete corresponding extents from cache ; when blocks are deleted from file (implying contents no longer ; valid for file-structured operations; the transition from allocated ; to deallocated file blocks also implies that the data contained ; in the block is not of sufficient interest to cache for ; non-file-structured logical i/o). ; ; Passed: ; R1 -> I/O packet from SMDEL in F11ACP ; P4,P5 = LBN of first block (P4 is MSP of dbl prec value ; P6.1, ; P6.2 = number of blocks (P6.1 is MSP of dbl prec value ; ; Action: ; All extents containing the deleted blocks are purged from cache. ; ; Returns: ; IO.SUC (no special status is set, nor any checked in SMDEL) ; FUNDEL: CMP I.TCB(R1),U.ACP(R5) ; is the requestor the owner? BNE PRIJMP ; nope, give priv error MOV #1,I.PRM+P2(R1) ; phoney up rqst length for search CALL SEARCH ; search for CED position in LBN BCS 90$ ; no overlapping extents MOV I.PRM+P4(R1),-(SP) ; extract the high order LBN ;DC430 BIT #DV.32B,U.CW1(R5) ; 32-bit LBNs used ;DC430 BNE 5$ ; if NE, yes, handle 32-BIT LBNs ;DC430 ;DC430 CLRB 1(SP) ; clear the high byte for 24-bit ;DC430 ;DC430 5$: CMP (SP)+,E.LBNL+2(R0) ; CED start before delete ;DC430 BLO 15$ ; if LO, yes, continue ;**-1 BHI 10$ ; nope, shorten it up ... CMP I.PRM+P5(R1),E.LBNL(R0) ; how about low order LBN BLOS 15$ ; if LO, delete the whole thing ;+ ; Since we are deleting in the middle of an extent, we must retain ; the "front-end" of this CED, and drop the remaining blocks from this ; CED. We also do NOT want to force an I/O for this housekeeping operation ;- 10$: MOV E.LBNH(R0),R3 ; get the high end LBN SUB I.PRM+P5(R1),R3 ; compute how much is dropped ;+ ; The one additional check is if the area to delete is only a ; portion of a single CED. At this point, if the amount to be deleted ; is greater than the total number of blocks to delete, then simply leave ; the entire CED intact ... ; ; R3 :== number of blocks to be removed from CED ;- TSTB I.PRM+P6.1(R1) ; more than 65.K blocks to remove? BNE 13$ ; if NE, yup, we can shorten it CMP R3,I.PRM+P6.2(R1) ; can we delete this many blocks? BHI 90$ ; if HI, nope, leave CED intact 13$: MOVB E.SIZE(R0),R2 ; get current CED size SUB R3,R2 ; compute new size MOVB R2,E.SIZE(R0) ; set the new size MOV I.PRM+P4(R1),-(SP) ; extract the high order LBN ;DC430 BIT #DV.32B,U.CW1(R5) ; are we using 32-bit LBNs ;DC430 BNE 14$ ; if NE, yes, continue ;DC430 ;DC430 CLRB 1(SP) ; clean up the high order part ;DC430 ;DC430 14$: MOV (SP)+,E.LBNH+2(R0) ; update this CED ending LBN ;DC430 MOV I.PRM+P5(R1),E.LBNH(R0) ; and the ending block LSP ;**-1 MOV E.LNXT(R0),R0 ; get the next, if available BEQ 90$ ; nothing more to overlap 15$: MOV I.PRM+P4(R1),R3 ; reset request base LBN BIT #DV.32B,U.CW1(R5) ; using 32-bit LBNs ;DC430 BNE 16$ ; if NE, yes, contunue ;DC430 BIC #177400,R3 ; clean off high order stuff ;DC430 ;DC430 16$: MOV I.PRM+P5(R1),R2 ;DC430 ADD I.PRM+P6.2(R1),R2 ; double precision count from ACP ;**-1 ADC R3 ADD I.PRM+P6.1(R1),R3 ; calculate end of request 20$: CMP R3,E.LBNL+2(R0) ; R0 -> CED within range? ;DC430 BHI 40$ ; yep, delete it and keep on going ;**-1 BLO 90$ ; nope, we've fallen out of range CMP R2,E.LBNL(R0) ; double precision compare BLOS 90$ ; we're done 40$: CALL ATTCED ; queue to extent, test if busy BCC 50$ ; not busy, trash it CLC ; busy, and we're queued to it RETURN ; let Phase 2 revisit 50$: MOV E.LNXT(R0),-(SP) ; save pointer to next extent ;+ ; Determine whether the entire extent should be deleted, or only ; a part of the extent ... ;- CMP R3,E.LBNH+2(R0) ; does this extent cover extras? ;DC430 BHI 70$ ; if HI, no, delete the whole exent ;**-1 BLO 60$ ; if LO, yes, update sizes CMP R2,E.LBNH(R0) ; now check the LSP BHIS 70$ ; if HIS, delete the extent ;+ ; Update the size parameter, and compute the new size ;- 60$: CALL UPDLBN ; update LBN parameters BCC 70$ ; if CC, just delete it ... CLR (SP) ; no more CED's to scan BR 80$ ; and continue the scan 70$: BICB #ES.WDF,E.STAT(R0) ; Extent not deferred, now. BISB #ES.DEL,E.STAT(R0) ; Extent to be deleted. 80$: CALL DETCED ; detach and delete MOV (SP)+,R0 ; get ptr to next CED BNE 20$ ; and go for next if one 90$: JMP FUNSUC ; go to $IOFIN and return .SBTTL Partition routines .SBTTL + VALPCB - Validate a partition given a PCB address ; ; Passed: ; R0 -> PCB to validate ; ; Returned: ; CC: PCB is valid ; CS: PCB is not valid ; VALPCB: MOV R1,-(SP) ; Work register (main PCB) MOV R2,-(SP) ; Work register (sub PCB) MOV #$PARHD,R1 ; Get PCB listhead 10$: MOV (R1),R1 ; Get a main partition BEQ 40$ ; End of list if EQ MOV R1,R2 ; Use R2 to run through subpartion 20$: MOV P.SUB(R2),R2 ; Get the next sub PCB BEQ 10$ ; Isn't one if EQ CMP R0,R2 ; Does this match? BNE 20$ ; If NE, no - try next one BIT #PS.COM, P.STAT(R2) ; Is this a common partition? BEQ 40$ ; If EQ, no BIT #P2.CHE,P.ST2(R2) ;Is this a cache partition? BEQ 40$ ;No if EQ; don't activate caching MOV KISAR6,-(SP) ; save kernel APR6 ;DC430 MOV P.REL(R2),KISAR6 ; map to the partition header ;DC430 MOVB #1,@#140000+H.CVER ; load in the cache version ;DC430 MOV (SP)+,KISAR6 ; restore kernel APR6 ;DC430 ;DC430 TST (PC)+ ; Match in PCB address, return CC ;DC430 ;DC430 40$: SEC ; No match, return CS ;**-1 MOV (SP)+,R2 MOV (SP)+,R1 RETURN .SBTTL Cache control routines .SBTTL + CHEACT - Activate cache for a device ; ; Passed: ; UCBX mapped in APR6 ; ; Returned: ; R0 := Contents lost ; ; Action: ; This routine will attempt to activate the cache for the ; device. If the UCBX specifies a PCB, it will be validated ; if it is valid then the map count ; of the partition (P.RMCT) will be incremented, and the cache ; activated for the device. ; CHEACT: MOV APR6.BASE+X.CPCB,R0 ;Get the PCB address BEQ 40$ ;None present if EQ; can't start CALL VALPCB ;Validate the partition BCS 40$ ;Failed if CS; skip the startup INCB P.RMCT(R0) ;Attach us to this partition BIS #P2.LMA, P.ST2(R0) ; Don't let partition be removed MOV R0, R3 ;Save PCB address in safe register MOV R1,-(SP) ;Save packet address MOV #SECSIZE,R1 ;Set size in R1 CALL $ALSEC ;Allocate secondary pool BCS 35$ ;Couldn't if CS ; ; Context: ; R0 -> Newly allocated block ; MOV R0,APR6.BASE+X.CSBA ;Set the cache statistics buffer MOV #</2>,R1 ;Size for initialization to zero MOV KISAR6,-(SP) ;Save UCBX mapping MOV R0,KISAR6 ;Map the new buffer MOV #APR6.BASE,R0 ;Set up its address 23$: CLR (R0)+ ;Initialize the buffer SOB R1, 23$ ;loop ;DC430 MOV R3, R0 ;Prepare parameter to $QSPIF ADD #P.CSBA, R0 ;Calculate the stat block listhead MOV KISAR6, R1 ;Point at new block to add CALL $QSPIF ;Add it to the end of the list MOV R5, APR6.BASE+S.UCB ;Point back to UCB MOV (SP)+,KISAR6 ;Reload UCBX mapping 35$: MOV (SP)+,R1 ;Get back saved packet address BISB #XC.ACT,APR6.BASE+X.CSTS ;Cache is now activated and PCB TST (PC)+ ; CLC, skip SEC 40$: SEC ; return failure flag to caller RETURN ;All done in validation .SBTTL + CHEDAC - Deactivate cache for a device ; ; Passed: ; UCBX mapped in APR6 ; ; Action: ; This routine will deactivate caching for a cached unit. ; First all activity must be run down, then the active status ; and context information is cleared. ; ; This routine handles the rundown, and the local internal routine ; DCDACT completes deactivation after all rundown is completed. ; ; If any CEDs exist, they will be purged. If any of them is busy ; packet will be queued to it and rundown will be propogated during ; Phase II. When the last CED is purged the packet will be queued ; completion during the next passs through Phase II (this ensures ; requests in the Phase II queue from the last CED will be completed ; before the deactivation completes). ; When the deactivation request finds no CEDs exist at entry the ; local internal routine DCDACT will be entered to finish deactivation ; ; ; Deactivation must handle queueing to interlock with busy extents. ; ; We set the flag X2.DEA when deactivation is started, and queue all ; I/O transfer requests while it is set. Control functions (IO.STC) ; directed to cache for the unit being deactivated will generally return ; privilege errors to avoid races and other nasty conditions ("SET" is ; an exception believed safe now). ; CHEDAC: BISB #X2.DEA,APR6.BASE+X.CST2 ; show cache deactivation in progress MOV APR6.BASE+X.CCED,R0 ; get first extent address if any BEQ DCDACT ; none, all CEDs deleted, finish MP.PAR ; map cache par 20$: CALL ATTCED ; make sure we can free CED (busy, etc) BCS 999$ ; it's busy and we're queued, exit MOV E.LNXT(R0),-(SP) ; Save ptr to next extent in LBN BISB #ES.DEL,E.STAT(R0) ; tell detach to delete CED BICB #ES.ERR,E.STAT(R0) ; reset the error so it will write CALL DETCED ; detach and delete the CED BCC 30$ ; if CC, it is gone!! CALL ATTCED ; attach to the CED w/ I/O pending TST (SP)+ ; clean the stack BR 999$ ; and pause for a while ... 30$: MOV (SP)+,R0 ; Get next extent in LBN list BNE 20$ ; keep on looping until all done CALLR Q2PHS2 ; finish after Phase 2 syncs in ; other requests still running down 999$: CLC ; send request to further proces RETURN .SBTTL + DCDACT - Deactivate cache - completion ; ; DCDACT - Rundown of all cache activity is done, now send all ; transfer requests queued during rundown along to the driver, ; then clear the status flags in the UCBX (XC.ACT and X2.DEA) ; and detach the UCBX from the cache partition (the resident ; mapped count in the PCB [P.RMCT] is used by the cacher as ; the mechanism to lock down cache data partitions.). Finally, ; return the I/O status for explicit deactivation requests or ; pass the request to the driver for implicit deactivations. ; DCDACT: MOV R1, -(SP) ; Save packet address 10$: MP.PAR ; ensure partition mapped MOV #APRD.BASE+H.DACTQ,R1 ; get queue listhead 12$: MOV R1,R0 ; hold previous chain element MOV (R0),R1 ; get the next list entry (if any) BEQ 20$ ; no, exit CMP I.UCB(R1),R5 ; is this packet for our device? BNE 12$ ; if NE, nope, try next packet MOV (R1),(R0) ; remove, close up list BNE 17$ ; not at end yet MOV R0,APRD.BASE+H.DACTQ+2 ; set end pointer to new end 17$: CALL .DRQRQ ; queue to driver BR 10$ ; and see if more to go 20$: MP.UCBX ; make sure UCBX is mapped BICB #XC.ACT, APR6.BASE+X.CSTS ; show cache not active BICB #X2.DEA,APR6.BASE+X.CST2 ; show cache rundown done MOV APR6.BASE+X.CPCB, R0 ; Get the PCB address of cache par DECB P.RMCT(R0) ; Detach from the partition BNE 50$ ; If NE, other devices still cached ; release fork block and clear pointer MOV R0,-(SP) ; save pcb ptr MOV KISAR6,-(SP) ; save UCBX mapping MP.PAR ; and map cache partition MOV H.FRK+APRD.BASE,R0 ; get frk block ptr BEQ 40$ ; never got one MOV 2(R0),H.FRK+APRD.BASE ; clear pointer BEQ 30$ ; was not used, ok FATAL$ BE.IDC ; internal consistency error 30$: TST -(R0) ; back up to deallocate UMR mask MOV #<6*2>,R1 ; set R1 to length to deallocated CALL $DEACB ; free pool 40$: MOV (SP)+,KISAR6 ; restore UCBX mapping MOV (SP)+,R0 ; restore register BIC #P2.LMA, P.ST2(R0) ; Otherwise this is the last one 50$: MOV APR6.BASE+X.CSBA, R1 ; Get cache statistics buffer BEQ 100$ ; None if EQ ADD #P.CSBA, R0 ; Calculate address of listhead CALL $GTSPK BCC 60$ ; If CC, sanity check FATAL$ BE.DDA ; double deallocation 60$: TST (R0)+ ; Is list empty? BNE 70$ ; If NE, no CLR (R0) ; P.DPCB must be null when REMing 70$: MOV R1, R0 ; Prepare parameter to $DESEC SECSIZE= /100 ; Size of CSB in secpol blocks MOV #SECSIZE, R1 ; Set size for deallocation CALL $DESEC ; Deallocate secondary pool buffer CLR APR6.BASE+X.CSBA ; Initialize the CSB pointer 100$: MOV (SP)+, R1 ; Pop I/O packet address CMP I.PRM+2(R1),#VV$CHE ; explicit or implicit? BNE 990$ ; implicit, send it along to driver CALLR FUNSUC ; explicit, rundown is finished 990$: CALL .DRQRQ ; implicit rundown complete CLR R1 ; no packet to forward, in case we ; never forked RETURN ; to caller .ENDC ; .IF DF D$$CHE .END